#include "StdAfx.h"
#include "FFEncondeInputPin.h"
#include "FFEncodeFilter.h"

#include "MediaFrame.h"
#include "MediaBuffer.h"
#include "fmtdefine.h"



#define  ABS(x) (x) < 0 ? -(x) : (x)

//////////   CFFEncodeInputPin  ///////////

CFFEncodeInputPin::CFFEncodeInputPin(CBaseFilter *pFilter,CCritSec *pLock,HRESULT *phr,LPCWSTR pName, EMediaType streamType)
	:	CBaseInputPin(L"CFFEncodeInputPin", pFilter, pLock, phr, pName)
	,	m_eType(streamType)
	,	m_validEvent(TRUE)
	,	m_pMediaBuffer(NULL)
{	
}

CFFEncodeInputPin::~CFFEncodeInputPin()
{
	if(m_pMediaBuffer){
		delete m_pMediaBuffer;
		m_pMediaBuffer = NULL;
	}
}

STDMETHODIMP CFFEncodeInputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
	*ppv = 0;
	return
		QI(IMediaSeeking)
		CBaseInputPin::NonDelegatingQueryInterface(riid, ppv); 
}

HRESULT CFFEncodeInputPin::CheckMediaType(const CMediaType *pmt)
{
	if( m_eType == MEDIA_TYPE_AUDIO &&
		pmt->majortype == MEDIATYPE_Audio && 
		pmt->subtype == MEDIASUBTYPE_PCM &&
		pmt->formattype == FORMAT_WaveFormatEx)
	{		
		WAVEFORMATEX* wfex = (WAVEFORMATEX*)pmt->pbFormat;
		if(wfex->wBitsPerSample == 16)
			return S_OK;
	}

	if( m_eType == MEDIA_TYPE_VIDEO &&
		pmt->majortype == MEDIATYPE_Video && 
		(pmt->subtype == MEDIASUBTYPE_RGB24
		|| pmt->subtype == MEDIASUBTYPE_YV12) )
		return S_OK;
	return E_FAIL;
}

HRESULT CFFEncodeInputPin::CompleteConnect(IPin *pReceivePin)
{
	HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin);
	if(FAILED(hr)) return hr;
	CMediaProp* pMediaProp = ((CFFEncodeFilter*)m_pFilter)->GetMediaProp();
	if(m_eType == MEDIA_TYPE_AUDIO){
		AudioAM2FM(&m_mt, pMediaProp->channels, pMediaProp->asampleRate);
	}else if(m_eType == MEDIA_TYPE_VIDEO){
		VideoAM2FM(&m_mt, pMediaProp->pixFmt, pMediaProp->width, pMediaProp->height);
	}

	if(!m_pMediaBuffer){
		m_pMediaBuffer = new CMediaBuffer(m_eType);
		if(!m_pMediaBuffer) return E_OUTOFMEMORY;
		if(!m_pMediaBuffer->InitBuffer())return E_OUTOFMEMORY;
	}
	return S_OK;
}

HRESULT CFFEncodeInputPin::BreakConnect()
{
	CAutoLock locLock(m_pLock);
	return CBaseInputPin::BreakConnect();
}


STDMETHODIMP CFFEncodeInputPin::Receive(IMediaSample *pSample)
{
	CAutoLock clock(&m_csReceive);
	HRESULT hr = CBaseInputPin::Receive(pSample);
	if(FAILED(hr)) return hr;	
	CMediaFrame* p = m_pMediaBuffer->GetNullFrame();
	if(!p) return E_FAIL;
	if(p->Copy(pSample, &m_mt)){
		m_pMediaBuffer->PushValidFrame(p);
	}else{
		m_pMediaBuffer->PushNullFrame(p);
	}
	return S_OK;
}


STDMETHODIMP CFFEncodeInputPin::EndOfStream()
{
	HRESULT hr = CBaseInputPin::EndOfStream();
	if(FAILED(hr)) return hr;	
	CMediaFrame* p = m_pMediaBuffer->GetNullFrame();
	if(!p) return E_FAIL;
	p->SetEOS();
	m_pMediaBuffer->PushValidFrame(p);
	return hr;
}

HRESULT CFFEncodeInputPin::Active()
{
	m_rtMaxStart = -1;
	m_bEOS = false;
	m_validEvent.Set();
	return __super::Active();
}

HRESULT CFFEncodeInputPin::Inactive()
{
	CAutoLock cLock(&m_csListValid);	
	return __super::Inactive();
}


STDMETHODIMP CFFEncodeInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
{
	CAutoLock clock(&m_csReceive);
	return CBaseInputPin::NewSegment(tStart, tStop, dRate);
}





